package com.studykun.client.util;

import java.util.ArrayList;

import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.InlineHTML;
import com.google.gwt.user.client.ui.Widget;
import com.studykun.client.model.Agent;
import com.studykun.client.ui.CategoryChart;
import com.studykun.client.ui.ChatBox;

public class ChatRoom implements Room, ProgressChangedHandler {
  private final ChatBox chatBox_;
  private final ArrayList<Presence> presences_ = new ArrayList<Presence>();
  private final ArrayList<EchoListener> echoListeners_ = new ArrayList<EchoListener>();
  private final SystemAgent systemAgent_;
  private final CategoryChart progressChart_;
  private final HasSyllabus hasSyllabus_;
  
  public ChatRoom(
      final ChatBox chatBox,
      final SystemAgent systemAgent,
      final HasSyllabus hasSyllabus,
      final CategoryChart progressChart) {
    chatBox_ = chatBox;
    systemAgent_ = systemAgent;
    hasSyllabus_ = hasSyllabus;
    progressChart_ = progressChart;
  }
  
  public void addEchoListener(
      final EchoListener echoListener) {
    echoListeners_.add(echoListener);
  }
  
  public void removeEchoListener(
      final EchoListener echoListener) {
    echoListeners_.remove(echoListener);
  }
  
  public Presence admit(
      final Agent agent)
  {
    for (final Presence presence : presences_) {
      if (presence.getAgent() == agent) {
        // Agent has already has a presence in the room.
        return null;
      }
    }
    
    if (!(agent instanceof SystemAgent)) {
      final String agentName = agent.getAvatar().avatarName();
      this.echo(EchoType.NORMAL, systemAgent_, agentName + " has entered the room.");
    }
    
    if (agent instanceof FiresProgressChangedEvent) {
      final FiresProgressChangedEvent firesProgressChangedEvent =
        (FiresProgressChangedEvent)agent;
      firesProgressChangedEvent.addProgressChangedHandler(this);
      onProgressChanged();
    }
    
    final Presence newPresence = new Presence(this, agent);
    presences_.add(newPresence);
    
    for (final Presence presence : new ArrayList<Presence>(presences_)) {
      presence.onAdmit(agent, this);
    }

    this.onAdmit(agent, this);

    return newPresence;
  }

  public void echo(
      final EchoType echoType,
      final Agent agent,
      final String message)
  {
    final InlineHTML messageLabel = new InlineHTML(message);
    displayEcho(echoType, agent, messageLabel);
    publishEcho(echoType, agent, message);
  }

  public void echo(
      final EchoType echoType,
      final Agent agent,
      final Widget widget) {
    displayEcho(echoType, agent, widget);
    publishEcho(echoType, agent, widget.getElement().getInnerText());
  }
  
  private void displayEcho(
      final EchoType echoType,
      final Agent agent,
      final Widget widget) {
    switch (echoType) {
    case NORMAL:
      final FlowPanel entry = agent.getAvatar().makeEntry();
      entry.add(widget);
      chatBox_.add(entry);
      break;
    }
  }
  
  private void publishEcho(
      final EchoType echoType,
      final Agent agent,
      final String message)
  {
    for (final EchoListener echoListener : echoListeners_) {
      echoListener.onEcho(echoType, this, agent, message);
    }
  }

  public void onAdmit(
      final Agent agent,
      final Room room) {
    // No action.
  }

  public void onProgressChanged() {
    progressChart_.setCategoryQuantities(
        hasSyllabus_.getSyllabus().getProgress());
  }

  public void evict(
      final Agent agent) {
    for (final Presence presence : presences_) {
      if (presence.getAgent() == agent) {
        if (agent instanceof FiresProgressChangedEvent) {
          final FiresProgressChangedEvent firesProgressChangedEvent =
            (FiresProgressChangedEvent)agent;
          firesProgressChangedEvent.removeProgressChangedHandler(this);
        }
        presences_.remove(presence);
        presence.onEvict(agent, this);
        this.onEvict(agent, this);
        onProgressChanged();
        break;
      }
    }
  }

  public boolean hasPresent(
      final Agent agent) {
    for (final Presence presence : presences_) {
      if (presence.getAgent() == agent) {
        return true;
      }
    }
    return false;
  }

  public void onEvict(
      final Agent agent,
      final Room room) {
    // No action.
  }
}
